#ifndef GPU_BASE_CUDA_H
#define GPU_BASE_CUDA_H

#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <math_constants.h>
#include <sm_20_intrinsics.h>  // 关键：提供 __syncthreads() 声明
#include <math_constants.h>     // CUDA 数学常量（如 PI）
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept>
#include <cstdio>
#include <cmath>
#include <limits>
#include <cairo/cairo.h>
#include <cairo/cairo-pdf.h>  // 必须包含 PDF 专用头文件（核心！很多人只包含 cairo.h 导致错误）
#include <opencv2/opencv.hpp>
#include <random>
#include <chrono> // 新增：std::chrono 所在头文件
#include <algorithm> // 后续 GPU 归约用到 std::max_element，建议补充
#include <numeric>  // 用于功率谱计算中的累加操作

// -------------------------- 全局常量定义（兼容高维，2D默认） --------------------------
template <typename Float = float>
constexpr Float PI = CUDART_PI_F;
constexpr int MAX_DIMENSIONS = 32;   // 最大支持维度（避免GPU栈溢出）
constexpr int CUDA_BLOCK_SIZE = 256; // CUDA线程块大小（适配GPU warp）

// 可视化常量（仅2D有效）
constexpr int SNAP_VIS_SIZE = 512;  // 快照默认尺寸（512x512）
template <typename Float = float>
constexpr Float SNAP_POINT_RAD = 3.0f; // 点绘制半径
const cv::Scalar SNAP_BG_COLOR = cv::Scalar(255, 255, 255); // 白色背景
const cv::Scalar SNAP_POINT_COLOR = cv::Scalar(0, 0, 0); // 黑色点（RGB）

// 快照默认参数（补充基类未初始化的默认值）
// 快照相关常量（可根据需求调整）
#define SNAPSHOT_BASE_PATH "gbn_snapshots/"  // 快照文件输出基础路径
#define SNAPSHOT_FORMAT_MASK (SNAP_FORMAT_TXT | SNAP_FORMAT_PNG)  // 输出TXT+PNG
#define SNAPSHOT_CONDITION SnapshotCondition::VISUAL_CHANGE  // 按视觉变化触发快照
#define SNAPSHOT_MAX_DIST_THRESHOLD 3.0f  // 视觉变化阈值（3像素）
// 快照格式枚举（高维自动过滤2D格式）
constexpr int SNAP_FORMAT_TXT = (1 << 0);  // 1: TXT（支持所有维度）
constexpr int SNAP_FORMAT_PNG = (1 << 1);  // 2: PNG（仅2D）
constexpr int SNAP_FORMAT_PDF = (1 << 2);  // 4: PDF（仅2D）

// 快照触发条件枚举
enum class SnapshotCondition {
    VISUAL_CHANGE = 1,  // 视觉变化触发（仅2D有效）
    POWER_OF_TWO = 2,   // 2的幂次触发（支持高维）
    EVERY_ITER = 3      // 每次迭代触发（支持高维）
};

// -------------------------- 基础数据结构（高维兼容版） --------------------------
/**
 * 高维点结构（默认2D，支持动态维度）
 * @tparam Float 浮点类型（float/double）
 */
template <typename Float = float>
struct Point {
    std::vector<Float> coords; // 动态存储各维度坐标（如2D: [x,y]）

    // 构造函数：指定维度（默认2D）
    Point(int dims = 2);

    // 重载[]运算符：便捷访问维度坐标
    Float& operator[](int idx);
    const Float& operator[](int idx) const;

    // 获取维度数量
    int getDims() const;
};


// -------------------------- GPU核函数声明（高维兼容版） --------------------------
/**
 * 计算高维点集对应点的平方距离（GPU核函数）
 * @tparam Float 浮点类型（float/double）
 * @param N 点集数量
 * @param dims 点集维度
 * @param d_p 目标点集（GPU，扁平化数组：N × dims）
 * @param d_ref 参考点集（GPU，同d_p格式）
 * @param d_dist_sq 输出：平方距离数组（GPU，长度=N）
 */
template <typename Float>
__global__ void computeDistSqKernel(int N, int dims, const Float* d_p, const Float* d_ref, Float* d_dist_sq);

// -------------------------- 工具函数声明（高维兼容版） --------------------------
/**
 * 生成[0, x)范围内的随机浮点数（线程安全）
 * @tparam Float 浮点类型（float/double）
 * @param x 上限值（需>0）
 * @return 均匀分布的随机浮点数
 */
template <typename Float = float>
Float randFloat(Float x);

// 新增：GPU归约计算最大值的核函数声明
template <typename Float>
__global__ void gpuReduceMaxKernel(const Float* d_arr, int N, Float* d_temp);

// 新增：主机端包装函数声明（供类内调用）
template <typename Float = float>
Float gpuReduceMax(const Float* d_arr, int N, Float* d_temp);

// -------------------------- GBNBasePointSet 类声明（高维核心类） --------------------------
/**
 * 高维点集管理类（默认2D，支持优化、快照、可视化）
 * @tparam Float 浮点类型（float/double，默认float）
 */
template <typename Float = float>
class GBNBasePointSet {
protected:
    // 1. 核心数据与GPU缓冲区（高维扁平化存储）
    int num_points;                  // 点集数量
    int dimensions;                  // 点集维度（默认2D）
    mutable std::vector<Point<Float>> h_points; // 主机端点集（CPU）
    Float* d_points;                 // 目标点集（GPU，扁平化：N × dims）
    Float* d_points_ref;             // 参考点集（GPU，快照用）
    Float* d_dist_sq;                // 平方距离缓冲区（GPU）
    Float* d_temp;                   // 临时缓冲区（GPU，归约用）

    // 2. 域参数（高维适配）
    Float out_black_ratio = 0.02f;   // 点集黑度比例（默认2%，仅2D可视化用）
    bool is_toroidal = true;      // 是否启用环形域（高维/2D均支持）
    std::vector<Float> domain_ranges; // 各维度域范围（如2D: [w,h]）
    Float unit;                      // 归一化单位（1/最大域范围）

    // 3. 快照参数（高维自动降级）
    std::string snap_base_path;     // 快照文件名前缀（快照地址）
    int frame_format;                // 快照格式掩码
    SnapshotCondition snap_cond;     // 快照触发条件
    int W, H;                        // 2D可视化尺寸
    Float margin;                    // 2D可视化边距
    int accum_iterations;            // 累计迭代次数
    int recorded_frames;             // 已记录快照数量

    // 内部辅助函数（protected，仅类内部使用）
    void init();                     // 初始化GPU缓冲区与参数
    void checkCudaErr(const std::string& msg) const; // 检查CUDA错误
    void adjustFrameFormat();        // 高维自动过滤2D格式

public:
    // 构造与析构函数
    //  随机生成点集的构造函数
    GBNBasePointSet(int num_points, 
        const std::vector<Float>& domain_ranges = {},
        const std::string& snap_path = SNAPSHOT_BASE_PATH);
    // 从TXT加载点集的构造函数
    GBNBasePointSet(const std::string& txt_file_name, 
        const std::vector<Float>& domain_ranges = {},
        const std::string& snap_path = SNAPSHOT_BASE_PATH);
    ~GBNBasePointSet();

    // 域参数设置接口
    void setToroidalMode(bool enable);

    // 点集数据传输接口（主机端↔GPU端）
    void copyHostToDevice() const;
    void copyDeviceToHost() const;
    void copyDeviceToRef() const;

    // 快照参数设置接口
    void initDefaultSnapshotParams();
    void generateSnapshot(int iter, bool force = false);
    void setOutBlackRatio(Float ratio);
    void setSnapshotCondition(SnapshotCondition cond);
    void setFrameBaseName(const std::string& base_name=SNAPSHOT_BASE_PATH);
    void setFrameFormat(int format_mask);
    void setFrameSize(int frame_w, int frame_h); // 仅2D有效

    // 多格式保存接口
    void saveTXT(const std::string& file_path) const;
    void savePNG(const std::string& file_path) const; // 仅2D有效
    void savePDF(const std::string& file_path) const; // 仅2D有效

    // 辅助计算接口（高维兼容）
    Float calcMaxPixelDist(); // 仅2D有效，高维返回0并警告
    Float calcAverageDist() const; // 支持高维最近邻距离

    //点集径向功率谱
    void calcRadialPowerSpectrum(std::vector<Float>& spectrum, int num_bins = 100, Float max_radius = 0.0f);
    void showRadialPowerSpectrum(const std::vector<Float>& spectrum, 
                             const std::string& window_name = "Radial Power Spectrum 径向功率谱", 
                             int plot_size = 512);
    void saveRadialPowerSpectrum(const std::vector<Float>& spectrum, 
                             const std::string& file_path, 
                             int plot_size = 800);                          
                             
    // 高维扩展接口：获取维度与域范围
    int getDimensions() const;
    std::vector<Float> getDomainRanges() const;
};


#endif // GPU_BASE_CUDA_H